import datetime
from datetime import datetime
import traceback
import os
import getpass
import textwrap
# Conexao às bases de dados
import pyodbc
#import pymssql
import sqlalchemy
from sqlalchemy import create_engine
# Analise
import pandas as pd
import numpy as np
#Visualization
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
import plotly
import plotly.express as px
import warnings
warnings.filterwarnings("ignore")
class color:
PURPLE = '\033[95m'
CYAN = '\033[96m'
DARKCYAN = '\033[36m'
BLUE = '\033[94m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED = '\033[91m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
END = '\033[0m'
#print(color.BOLD + 'Hello World !' + color.END)
pd.options.display.max_rows = 999
pd.options.display.max_columns = 200
pd.set_option('max_colwidth', 1000) # tamanho das colunas para exibição do conteúdo de textos longos
np.set_printoptions(threshold=1000)
# Formatar numeros float (2 casas decimais)
pd.set_option('display.float_format', lambda x: '%.2f' % x)
pd.set_option('display.float_format', lambda x: '{:.2f}'.format(x))
# Formatações para gráficos
sns.set(style="darkgrid") #cor da area dos plots
figsize = (10,10)
random_state = 123
fig = px.colors.qualitative.swatches()
fig.show()
Para um determinado dataframe, elimina-se espaços à direita e esquerda das palavras.
def remove_space (df):
for col in df.select_dtypes(include = ["object"]).columns:
df[col] = df[col].str.strip()
Para um determinado dataframe, são verificados:
def checar_df(df):
print(color.BOLD + color.RED + 'Informações do dataframe: ' + color.END)
df.info()
print(color.BOLD + color.RED + "\nNúmero de observacoes na base de dados: " + color.END, df.shape[0])
print('Total de ', df.shape[1], 'Colunas: ', df.columns.values.tolist())
print(color.BOLD + color.RED + "\nNúmero de valores unicos (Não inclui NaN): " + color.END)
display(df.nunique(dropna=True).to_frame(name='Contagem Unicos').sort_index())
print(color.BOLD + color.RED + "Número de valores nulos:" + color.END)
display(df.isnull().sum().sort_values(ascending=False).to_frame(name='Contagem Nulos').sort_index())
Para uma determinada lista de valores, são verificadas:
Os parâmetros de entrada para a função são:
# passar como parâmetro a lista de colunas para as quais se deseja obter os valores únicos existentes
def checar_val_colunas_df_lista(df, lista_colunas):
print(color.BOLD + color.RED + "Contagem de valores unicos (inclui NaN) e apresentação da lista de valores: \n"
+ color.END)
for column in lista_colunas:
print(column, ': ', len(df[column].unique()),'valores únicos \n',
df[column].sort_values().unique().tolist(), '\n')
Para uma determinada lista de valores, são verificadas:
Os parâmetros de entrada para a função são:
# passar como parâmetro o número máximo de valores únicos (n_unique)
# Ex. mostrar colunas e seus valores únicos apenas quando a coluna tem até N valores únicos
def checar_val_colunas_df_nunique(df, n_unique):
df_count_unique = df.nunique(dropna=True).to_frame(name='Contagem Unicos').sort_values(by='Contagem Unicos')
lista_colunas = df_count_unique[df_count_unique['Contagem Unicos'] <= n_unique].index
print(color.BOLD + color.RED + "Contagem de valores unicos (inclui NaN) e apresentação da lista de valores: "
+ color.END)
print(color.BOLD + color.RED + '(até', n_unique, 'valores únicos)\n' + color.END)
for column in lista_colunas:
print(column, ': ', len(df[column].unique()),'valores únicos \n',
df[column].sort_values().unique().tolist(), '\n')
Checa dois dataframes e imprime quais as colunas de um dataframe que não estão em outro dataframe.
def get_df_name(df):
name =[x for x in globals() if globals()[x] is df][0]
return name
def compara_dois_dataframes(df1, df2):
df1_col = df1.columns.values
df2_col = df2.columns.values
print(color.BOLD + 'Colunas inexistentes no', str(get_df_name(df1)) + color.END)
display([c2 for c2 in df2_col if c2 not in df1_col])
print(color.BOLD + 'Colunas inexistentes no' , str(get_df_name(df2)) + color.END)
display([c1 for c1 in df1_col if c1 not in df2_col])
Dado um dataframe, imprime um resumo das operações, valores contratados, períodos contemplados, entre outras informações.
def oper_info_resumidas(df):
tipo_oper = df['tipo_oper'].unique()[0]
print('Total de registros de Operações Contratadas na Forma %s: %d operações' % (tipo_oper, df.shape[0]))
print(' - Forma DIRETA: ', df[df['forma_de_apoio']=='DIRETA'].shape[0])
print(' - Forma INDIRETA: ', df[df['forma_de_apoio']=='INDIRETA'].shape[0])
print('\nTotal Valor Contratado (em R$ bilhões):',round(df['valor_contratado_reais'].sum()/1000000000,2))
print('Total Valor Desembolsado (em R$ bilhões):' ,round(df['valor_desembolsado_reais'].sum()/1000000000,2))
print(len(df['numero_do_contrato'].unique()), 'Contratos no período: ', \
np.min(df['data_da_contratacao']).date(), 'a', \
np.max(df['data_da_contratacao']).date())
print('Total de', len(df['municipio_codigo'].unique()),'municipios contemplados em',\
len(df['uf'].unique()),'estados.')
Dado um dataframe e a coluna de interesse (hue), cria um boxplot dos valores contratados quebrados pelo parâmetro "hue".
Por ex. Caso o hue seja forma de apoio (DIRETA/ INDIRETA), haverá boxes para cada possível valor do "hue".
def boxplot_vlr_contr_hue(df, hue, palette):
f, axes = plt.subplots(1, 1, figsize=(20, 12))
g = sns.boxplot(x='ano_contratacao', y='valor_contratado_log', hue=hue, data=df, palette=palette)
g.axhline(9.5, linestyle='--', linewidth = 1.5, color='r', label='Maiores outliers')
major_ticks = np.arange(0, 12, 1)
minor_ticks = np.arange(0, 12, 0.5)
axes.set_yticks(major_ticks)
axes.set_yticks(minor_ticks, minor=True)
axes.grid(which='both', axis='y')
xlocs, xlabels = plt.xticks()
ylocs, ylabels = plt.yticks()
plt.setp(xlabels, fontsize=16, rotation=90)
plt.setp(ylabels, fontsize=16)
axes.set(xlabel='');
axes.set_ylabel('Valor Contratado (log)', fontsize=16)
axes.set_title('Valores Contratados (log) por Ano e %s' %hue, fontsize=20)
axes.legend(fontsize=16)
plt.show()
Axis são definidos automaticamente na função abaixo.
def boxplot_vlr_contr_hue_axis(df, hue, palette):
f, axes = plt.subplots(1, 1, figsize=(20, 12))
g = sns.boxplot(x='ano_contratacao', y='valor_contratado_log', hue=hue, data=df, palette=palette)
g.axhline(9.5, linestyle='--', linewidth = 1.5, color='r', label='Maiores outliers')
#major_ticks = np.arange(0, 12, 1)
#minor_ticks = np.arange(0, 12, 0.5)
#axes.set_yticks(major_ticks)
#axes.set_yticks(minor_ticks, minor=True)
#axes.grid(which='both', axis='y')
xlocs, xlabels = plt.xticks()
ylocs, ylabels = plt.yticks()
plt.setp(xlabels, fontsize=16, rotation=90)
plt.setp(ylabels, fontsize=16)
axes.set(xlabel='');
axes.set_ylabel('Valor Contratado (log)', fontsize=16)
axes.set_title('Valores Contratados (log) por Ano e %s' %hue, fontsize=20)
axes.legend(fontsize=16)
plt.show()
Dado um dataframe consolidado (operações automaticas e não automaticas), gera gráfico com a distribuição dos valores contratados conforme o tipo de operação (Automática/ Não Automática) e a forma de apoio (Direta/Indireta), ao longo dos anos.
Foi utilizado o dataframe consolidado pois não há a forma Indireta para as Operações Automáticas.
def plot_val_contr_oper_apoio(df_consol):
t_vlr_forma_apoio = df_consol.groupby(['ano_contratacao','Oper_Apoio'])['valor_contratado_reais'].sum()/1000000
t_vlr_forma_apoio = t_vlr_forma_apoio.reset_index() # em milhoes
#print(color.BOLD + color.BLUE + 'Valores Contratados (em milhões) por Operação e Forma de apoio '+ color.END)
#print(color.BOLD + color.BLUE + 75*'*' + color.END)
# display(t_vlr_forma_apoio) # tabela com os valores para cada Oper_apoio, por Ano
fig = px.bar(t_vlr_forma_apoio.sort_values(by='ano_contratacao', ascending=True),
x='ano_contratacao', y='valor_contratado_reais', color='Oper_Apoio',
color_discrete_sequence=px.colors.qualitative.Dark2,
barmode = 'group', width=900, height=600)
fig.update_layout(title={'text': "Valores Contratados por Tipo de Operação e Forma de apoio",
'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top'},
yaxis=dict(title='Valor Contratado (milhões)', titlefont_size=14,tickfont_size=14),
xaxis=dict(title=''),
legend=dict(x=0.05,y=0.9))
fig2 = px.line(t_vlr_forma_apoio.sort_values(by='ano_contratacao', ascending=True),
x='ano_contratacao', y='valor_contratado_reais', color='Oper_Apoio',
color_discrete_sequence=px.colors.qualitative.Dark2,
width=900, height=600)
fig2.update_layout(title={'text': "Valores Contratados por Tipo de Operação e Forma de apoio",
'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top'},
yaxis=dict(title='Valor Contratado (milhões)', titlefont_size=14,tickfont_size=14),
xaxis=dict(title=''),
legend=dict(x=0.05,y=0.9))
fig.update_xaxes(nticks=20, tickangle = 45); fig2.update_xaxes(nticks=20, tickangle = 45) # 20 anos
fig.show(); fig2.show()
Dado um dataframe, gera gráfico com a evolução dos valores contratados/ desembolsados ao longo dos anos.
def plot_evol_val_contr_desemb(df):
tipo_oper = df['tipo_oper'].unique()[0]
# Valor total dos contratos por ano
t_vlr_contr_ano = df.groupby(['ano_contratacao'])['valor_contratado_reais'].sum()/1000000000 # em bilhoes
t_vlr_desemb_ano = df.groupby(['ano_contratacao'])['valor_desembolsado_reais'].sum()/1000000000 # em bilhoes
# Calcula a Taxa de crescimento do Valor total dos contratos (de um ano a outro)
tx = []
tx.append(0)
list = t_vlr_contr_ano.sort_index(ascending=True).values
for i in range(t_vlr_contr_ano.shape[0]-1):
dif = np.round((list[i+1] - list[i]) / list[i] * 100,2)
tx.append(dif)
tx_d = []
tx_d.append(0)
list = t_vlr_desemb_ano.sort_index(ascending=True).values
for i in range(t_vlr_desemb_ano.shape[0]-1):
dif = np.round((list[i+1] - list[i]) / list[i] * 100,2)
tx_d.append(dif)
total_vlr_contr_ano = pd.DataFrame({'Total Valor Contratado' : t_vlr_contr_ano, 'Taxa Contr(%)' : tx})\
.reset_index()
total_vlr_desemb_ano = pd.DataFrame({'Total Valor Desembolsado' : t_vlr_desemb_ano, 'Taxa Desemb(%)' : tx_d})\
.reset_index()
total_vlres = pd.merge(left=total_vlr_contr_ano, right=total_vlr_desemb_ano,
how='inner',
on=['ano_contratacao'])
#display(total_vlr_contr_ano)
# Setar intervalo para x axis
ano_min = np.min(total_vlr_contr_ano['ano_contratacao'])
ano_max = np.max(total_vlr_contr_ano['ano_contratacao'])
# Grafico
fig = plt.figure(figsize = (18,10))
sns.lineplot(x='ano_contratacao', y='Total Valor Contratado',
data=total_vlres, color ='g', linewidth=2.5, label='Valor Contratado')
sns.lineplot(x='ano_contratacao', y='Total Valor Desembolsado',
data=total_vlres, color ='b', linewidth=1.5, label='Valor Desembolsado', linestyle='--')
# Configuracoes
ax = plt.gca()
ax.set_title("Operações do Tipo %s: Total dos Valores Contratados/Desembolsados por Ano" % tipo_oper, fontsize=15)
ax.set(xlabel=''),
ax.set_ylabel('Total (em bilhões)', fontsize=16)
max_y = np.max(df.groupby(['ano_contratacao'])['valor_contratado_reais'].sum()/1000000000)
max_y = round(max_y*1.1,0)
max_y
major_yticks = np.arange(0, max_y, 5); ax.set_yticks(major_yticks)
ax.tick_params(axis='x', labelsize=14); ax.tick_params(axis='y', labelsize=14)
plt.xticks(np.arange(ano_min, ano_max+1, 1))
ax.legend(fontsize=14)
plt.show()
Identifica o Total de municípios existentes nas UFs presentes no dataframe.
# Total de Municipios investidos por UF
def stats_tot_mun_uf1(df):
print('Total de Municipios: ', len(df['municipio_codigo'].unique()), 'Municípios')
print('Total de Municípios por Estado: ')
display(
df[['uf','municipio_codigo']].drop_duplicates().groupby('uf')['municipio_codigo'].count()\
.sort_values(ascending=False).reset_index())
Identifica o Total de municípios existentes nas UFs presentes no dataframe, comparando-se com o total de municipios do IBGE.
# Total de Municipios existentes/ investidos por UF
def stats_tot_mun_uf(df):
print('Total de Municipios IBGE: ', len(ibge['COD_IBGE'].unique()), 'Municípios')
print('Total de Municipios investidos: ', len(df['municipio_codigo'].unique()), 'Municípios')
df_plot = df[['uf','municipio_codigo']].drop_duplicates().groupby('uf')['municipio_codigo'].count()\
.sort_values(ascending=False).reset_index()
df_plot.columns=['uf','Total Municipios investidos']
df_ibge = ibge.groupby(['SIGLA_UF'])['COD_IBGE'].count().reset_index()
df_ibge.columns=['uf','Total Municipios IBGE']
#Juntar info de municipios investidos e total de municipios existentes conforme IBGE
df_munic = pd.merge(df_plot, df_ibge, on='uf', how='inner')
df_munic2 = df_munic.melt(id_vars='uf').rename(columns=str.title)
f, axes = plt.subplots(1, 1, figsize = (18,10))
g = sns.barplot(x='Uf', y='Value', hue='Variable', data=df_munic2.sort_values(by='Value', ascending=False))
axes.set_title('Total de Municipios com investimentos - por UF', fontsize=16)
axes.set(xlabel='')
axes.set_ylabel('Total de municipios', fontsize=16)
xlocs, xlabels = plt.xticks()
plt.setp(xlabels, fontsize=13, rotation=0)
axes.legend(fontsize=16)
#print('Total de Municípios por Estado: ')
#display(df_munic2)
Ações:
%%time
df_auto = pd.read_csv('Operacoes_indiretas_automaticas.csv', sep=';', decimal=',',
parse_dates=['data_da_contratacao'],
low_memory=False)
df_auto['data_da_contratacao'] = pd.to_datetime(df_auto['data_da_contratacao'], format='%Y-%m-%d')
columns_object = ['municipio_codigo']
for c in columns_object:
df_auto[c] = df_auto[c].astype(int).astype(str)
Ações:
%%time
df_nauto = pd.read_csv('Operacoes_nao_automaticas.csv', sep=';', decimal=',',
parse_dates=['data_da_contratacao'],
low_memory=False)
df_nauto['data_da_contratacao'] = pd.to_datetime(df_nauto['data_da_contratacao'], format='%Y-%m-%d')
columns_object = ['municipio_codigo','numero_do_contrato']
for c in columns_object:
df_nauto[c] = df_nauto[c].astype(int).astype(str)
#df_nauto.sample(3).T
list_col_string = ['COD_IBGE','COD_SIAFI','COD_UE_TSE_2016','CAPITAL']
dict_dtype = {column : 'str' for column in list_col_string}
ibge = pd.read_csv('ibge.csv', sep=';', dtype = dict_dtype, low_memory=False)
ibge.info()
ibge.head(5).T
remove_space(df_nauto)
remove_space(df_auto)
Campos com somente um valor são descartados do dataframe.
checar_val_colunas_df_nunique(df_nauto, 1)
del df_nauto['tipo_de_excepcionalidade']
df_nauto.insert(0, 'ano_contratacao', pd.DatetimeIndex(df_nauto['data_da_contratacao']).year)
df_auto.insert(0, 'ano_contratacao', pd.DatetimeIndex(df_auto['data_da_contratacao']).year)
compara_dois_dataframes(df_auto, df_nauto)
A partir dos dados acima, faz-se necessário uniformizar nomes de colunas, para que os dataframes de operações automáticas e não automáticas possam ser consolidados em um único dataframe.
df_auto = df_auto.rename(columns={'valor_da_operacao_em_reais':'valor_contratado_reais',
'situacao_da_operacao':'situacao_do_contrato' })
df_nauto = df_nauto.rename(columns={'cnpj':'cpf_cnpj',
'cnpj_da_instituicao_financeira_credenciada':'cnpj_do_agente_financeiro'})
compara_dois_dataframes(df_auto, df_nauto)
Compara-se as listas de colunas dos 2 dataframes, para a inclusão correta das colunas ausentes.
print('Colunas do dataframe df_auto:\n', df_auto.columns.values.tolist())
print('\nColunas do dataframe df_nauto:\n', df_nauto.columns.values.tolist())
df_auto.insert(3, 'descricao_do_projeto', 'Não se aplica')
df_auto.insert(7, 'numero_do_contrato', 'Não se aplica')
df_auto.insert(32, 'tipo_de_garantia', 'Não se aplica')
# Add Coluna para Tipo da Operação: Automatica e não Automatica
df_auto.insert(0, 'tipo_oper', 'Automatica')
df_nauto.insert(0, 'tipo_oper', 'Nao_Automatica')
print('Colunas do dataframe df_auto:\n', df_auto.columns.values.tolist())
print('\nColunas do dataframe df_nauto:\n', df_nauto.columns.values.tolist())
# Criação de dataframe consolidado
df_consol = pd.concat([df_auto,df_nauto])
df_consol = df_consol.reset_index(drop=True)
df_consol.shape
conditions = [
(df_consol['tipo_oper']=='Nao_Automatica') & (df_consol['forma_de_apoio']=='DIRETA'),
(df_consol['tipo_oper']=='Nao_Automatica') & (df_consol['forma_de_apoio']=='INDIRETA'),
(df_consol['tipo_oper']=='Automatica') & (df_consol['forma_de_apoio']=='INDIRETA')]
oper_apoio = ['DIRETA Não Automatica','INDIRETA Não Automatica','INDIRETA Automatica']
df_consol['Oper_Apoio'] = np.select(conditions, oper_apoio)
print('Total de registros das Operações:')
display(df_consol['Oper_Apoio'].value_counts())
Inserir coluna com log dos valores, para facilitar a construção de histogramas e gráficos boxplots.
df_consol.insert(11, 'valor_contratado_log', np.log10(df_consol['valor_contratado_reais']+0.01))
df_consol.insert(13, 'valor_desembolsado_log', np.log10(df_consol['valor_desembolsado_reais']+0.01))
#df_consol.iloc[:, 10:13].head(10)
df_consol.columns
Para um determinado dataframe, são verificados: (checar_df)
Para uma determinada lista de valores, são verificadas: (checar_val_colunas_df_nunique)
checar_df(df_auto)
lista_col_interesse = ['uf']
checar_val_colunas_df_lista(df_auto, lista_col_interesse)
checar_val_colunas_df_nunique(df_auto, 20)
checar_df(df_nauto)
lista_col_interesse = ['uf']
checar_val_colunas_df_lista(df_nauto, lista_col_interesse)
# Observação: o que seria UF = IE?
checar_val_colunas_df_nunique(df_nauto, 20)
ano_min = np.min(df_consol['ano_contratacao'])
ano_max = np.max(df_consol['ano_contratacao'])
lista_anos = np.arange(ano_min, ano_max,1)
vlr_contr_soma_ano_bi = (df_consol.groupby(['ano_contratacao'])\
['valor_contratado_reais'].sum()/1000000000).reset_index() # em bilhoes
Verificação do comportamento estatístico dos valores contratados (considerando-se todos os valores em todos os anos).
print(color.BOLD + color.BLUE + 'Estatisticas - Operações Automaticas' + color.END)
print(color.BOLD + color.BLUE + 50*'*' + color.END)
display(df_auto['valor_contratado_reais'].describe())
print(color.BOLD + color.BLUE + 'Estatisticas - Operações Não Automaticas')
print(color.BOLD + color.BLUE + 50*'*' + color.END)
display(df_nauto['valor_contratado_reais'].describe())
print(color.BOLD + color.BLUE + 'Estatisticas - Dataframe consolidado')
print(color.BOLD + color.BLUE + 50*'*' + color.END)
display(df_consol['valor_contratado_reais'].describe())
**Avaliação**:
Resumo das Operações em números...
Agrupamento/ Soma de todos os valores contratados no ano.
print('Total dos Valores Contratados (em bilhões) nos anos de %s a %s: ' % (ano_min, ano_max),
np.round(df_consol['valor_contratado_reais'].sum()/1000000000))
display(vlr_contr_soma_ano_bi)
f, axes = plt.subplots(1, 1, figsize=(18, 10))
g = sns.lineplot(x='ano_contratacao', y='valor_contratado_reais',
data=vlr_contr_soma_ano_bi, color ='g', linewidth=2.5, label='Valor Contratado')
g.axhline(110, linestyle='--', linewidth = 1.5, color='red', label='Pico da Soma dos valores contratados')
axes.set_title('Total/Soma do Valor Contratado - por Ano', fontsize=20)
axes.set_ylabel('Valor Contratado (bilhões)', fontsize=14)
axes.set(xlabel='')
xlocs, xlabels = plt.xticks()
ylocs, ylabels = plt.yticks()
plt.setp(xlabels, fontsize=14, rotation=90)
plt.setp(ylabels, fontsize=14)
plt.xticks(np.arange(ano_min, ano_max+1, 1))
plt.legend(fontsize=14)
plt.show()
O objetivo deste gráfico é exibir a soma de todos os valores contratados, por ano, ao longo dos anos - a fim de notarmos a tendência ou não de crescimento.
Observação: Comparando-se este gráfico com o boxplot seguinte (BoxPlot da distribuição dos Valores Contratados), percebe-se claramente que o pico de investimentos nos anos de 2009 e 2012 foi devido a contratos pontuais. Em outras palavras: aparentemente, não houve um aumento expressivo na quantidade de contratos. O que aparentemente houve foi que apenas poucos contratos (2 a 3 contratos específicos) de valor muito elevado resultaram na ocorrência dos picos.
Verificação da dispersão dos valores contratados ao longo dos anos.
f, axes = plt.subplots(1, 1, figsize=(16, 6))
g = sns.boxplot(x='ano_contratacao', y='valor_contratado_reais', data=df_consol)
g.axhline(5000000000, linestyle='--', linewidth = 1.0, color='red', label='Contratos pontuais bastante elevados')
g.axhline(3000000000, linestyle='--', linewidth = 1.0, color='orange', label='Contratos acima de 3 bilhões')
axes.set_title('Distribuição dos Valores Contratados - 2002 a 2021', fontsize=20)
axes.set_ylabel('Valor Contratado (bruto)', fontsize=14)
axes.set(xlabel='')
ylocs, ylabels = plt.yticks()
plt.setp(xlabels, fontsize=14, rotation=90)
plt.setp(ylabels, fontsize=14)
plt.legend(fontsize=14)
plt.show()
**Avaliação**:
A grande variabilidade dos valores contratados dificulta o entendimento a respeito da sua distribuição para valores mais baixos. Desta forma, será utilizada a notação logarítima nos próximos gráficos.
f, axes = plt.subplots(1, 1, figsize=(16, 8))
g = sns.boxplot(x=df_consol['ano_contratacao'],
y=df_consol['valor_contratado_log'], ax=axes, color='lightblue')
g.axhline(9.5, linestyle='--', linewidth = 1.5, color='r', label='Maiores outliers')
g.axhline(3.5, linestyle='--', linewidth = 1.5, color='orange', label='Valores irrisórios (abaixo de $3000)')
major_ticks = np.arange(0, 12, 1)
minor_ticks = np.arange(0, 12, 0.5)
axes.set_yticks(major_ticks)
axes.set_yticks(minor_ticks, minor=True)
axes.grid(which='both', axis='y')
xlocs, xlabels = plt.xticks()
ylocs, ylabels = plt.yticks()
plt.setp(xlabels, fontsize=14, rotation=90)
plt.setp(ylabels, fontsize=14)
axes.set_title('Distribuição dos Valores Contratados (log) - 2002 a 2021', fontsize=16)
axes.set(xlabel='');
axes.set_ylabel('Valor Contratado (log)', fontsize=14)
axes.legend(fontsize=13, loc='upper center')
plt.show()
**Avaliação**:
boxplot_vlr_contr_hue(df_consol, 'forma_de_apoio', 'viridis')
**Avaliação**:
boxplot_vlr_contr_hue(df_consol, 'tipo_oper', 'plasma')
**Avaliação**:
boxplot_vlr_contr_hue(df_consol, 'porte_do_cliente', 'hot_r')
**Avaliação**:
boxplot_vlr_contr_hue(df_consol, 'natureza_do_cliente', 'Set1')
**Avaliação**:
boxplot_vlr_contr_hue(df_consol, 'setor_bndes', 'hsv')
boxplot_vlr_contr_hue(df_consol, 'setor_cnae', 'hsv')
**Avaliação - Setor BNDES**:
**Avaliação - Setor CNAE**:
Nota:
df_consol_mun = pd.merge(df_consol, ibge[['COD_IBGE', 'REGIAO', 'SIGLA_UF', 'NOME_UF', 'NOME_MUNICIPIO','CAPITAL','POP2013',
'LAT', 'LNG', 'ALT','POP2013', 'CAPITAL']],
left_on='municipio_codigo',
right_on='COD_IBGE',
how='left', indicator=True)
Regioes = ibge['REGIAO'].sort_values().unique()
print('Regiões: ', Regioes)
print('\nTotal de registros do dataframe df_consol_mun:', df_consol_mun.shape[0])
print('Total de registros com os dados do IBGE atualizados:')
display(df_consol_mun['_merge'].value_counts())
print('Quantidade de registros de operações sem a informação de Municipio:')
display(df_consol_mun[df_consol_mun['_merge']=='left_only'][['municipio']].value_counts())
print('Apresenta as UFs que contém algum campo de Municipio sem informação:')
display((df_consol_mun[df_consol_mun['_merge']=='left_only'][['uf']].value_counts()).index.values)
# Retirar os registros sem informação de municipio
df_consol_mun = df_consol_mun[df_consol_mun['_merge'] == 'both']
df_consol_mun.shape
Exibe o total de municipios por UF que ja receberam investimentos em algum ano, em comparação com o total de municipios existentes em cada UF.
#stats_tot_mun_uf(df_consol_mun[df_consol_mun['ano_contratacao']==2002])
stats_tot_mun_uf(df_consol_mun)
**Avaliação**:
#Verificação de algum ano especifico
#stats_tot_mun_uf(df_consol_mun[df_consol_mun['ano_contratacao']==2003])
df_vlr_ano_mun = df_consol_mun.groupby(['ano_contratacao','REGIAO','uf','NOME_UF','municipio_codigo','NOME_MUNICIPIO',\
'LAT','LNG','ALT'])['valor_contratado_reais'].agg(['sum','min','max','count'])\
.reset_index()
df_vlr_ano_mun = df_vlr_ano_mun.rename(columns={'sum':'Soma_ValorContr',
'min':'Menor_ValorContr',
'max':'Maior_ValorContr',
'count':'Total_Contr'})
df_vlr_ano_mun.insert(10, 'Soma_ValorContr_log', np.log10(df_vlr_ano_mun['Soma_ValorContr']+0.01))
print(df_vlr_ano_mun.shape)
display(df_vlr_ano_mun.head())
Para cada UF, em cada ano, exibe total de municipios contemplados com investimentos
total_mun_UF = df_vlr_ano_mun.groupby(['ano_contratacao','REGIAO', 'uf'])['municipio_codigo'].nunique().reset_index()
total_mun_UF.columns = ['ANO','REGIAO', 'UF','QTD_MUNIC']
total_mun_UF = total_mun_UF.sort_values(by=['ANO','QTD_MUNIC'], ascending=[True, False])
ix = 1
fig = plt.figure(figsize = (20,10))
cores = sns.color_palette("tab20c")
for R in Regioes:
if ix <= 1:
ax2 = fig.add_subplot(1,1,1)
my_order = total_mun_UF[total_mun_UF['REGIAO']==R].groupby(['UF'])['QTD_MUNIC']\
.count().sort_values(ascending=True).iloc[::-1].index
sns.barplot(x='UF', y='QTD_MUNIC', hue='ANO',
data=total_mun_UF[total_mun_UF['REGIAO']==R],
ax=ax2, palette=cores, order=my_order)
ax2.set_title('Total Municipios financiados na Regiao %s - 2002 a 2021' %R, fontsize=20)
ax2.set_ylabel(''); ax2.set_xlabel('')
xlocs, xlabels = plt.xticks()
ylocs, ylabels = plt.yticks()
plt.setp(xlabels, rotation=0, fontsize=16)
plt.setp(ylabels, fontsize=16)
ix = ix +1
if ix == 2:
fig = plt.figure(figsize = (20,10))
ix =1
plt.tight_layout()
**Avaliação**:
Os plots acima foram criados para facilitar a visualização de quais UFs, dado um determinado ano, estão com um maior número de municípios recebendo mais investimentos. Desta forma, pode-se verificar, por exemplo:
Para cada UF, em cada ano, exibe o total de valores investidos.
total_vlr_cntr_UF = df_vlr_ano_mun.groupby(['ano_contratacao','REGIAO', 'uf'])['Soma_ValorContr'].sum().reset_index()
total_vlr_cntr_UF.columns = ['ANO','REGIAO', 'UF','Soma_ValorContr']
total_vlr_cntr_UF = total_vlr_cntr_UF.sort_values(by=['ANO','Soma_ValorContr'], ascending=[True, False])
ix = 1
fig = plt.figure(figsize = (20,10))
cores = sns.color_palette("tab20c")
for R in Regioes:
if ix <= 1:
ax2 = fig.add_subplot(1,1,1)
my_order = total_vlr_cntr_UF[total_vlr_cntr_UF['REGIAO']==R].groupby(['UF'])['Soma_ValorContr']\
.count().sort_values(ascending=True).iloc[::-1].index
sns.barplot(x='UF', y='Soma_ValorContr', hue='ANO',
data=total_vlr_cntr_UF[total_vlr_cntr_UF['REGIAO']==R],
ax=ax2, palette=cores, order=my_order)
ax2.set_title('Total Valores Contratados na Regiao %s - 2002 a 2021' %R, fontsize=20)
ax2.set_ylabel(''); ax2.set_xlabel('')
xlocs, xlabels = plt.xticks()
ylocs, ylabels = plt.yticks()
plt.setp(xlabels, rotation=0, fontsize=16)
plt.setp(ylabels, fontsize=16)
ix = ix +1
if ix == 2:
fig = plt.figure(figsize = (20,10))
ix =1
plt.tight_layout()
**Avaliação**:
O plot acima procura mostrar o total investido em cada UF, para cada ano. Pode-se perceber:
%%time
features_categoricas = ['uf']
ix = 1
fig = plt.figure(figsize = (55,20))
# c = para cada coluna
for c in list(df_consol[features_categoricas]):
if ix <= 3:
ax2 = fig.add_subplot(2,3,ix+2)
my_order = df_consol.groupby(by=c)['valor_contratado_log'].median().sort_values(ascending=False).iloc[::-1].index
sns.stripplot(x=df_consol[c], y=(df_consol['valor_contratado_log']), ax=ax2, order=my_order, linewidth=0.5)
ax2.set(ylabel="valor_contratado_log")
locs, labels = plt.xticks()
plt.setp(labels, rotation=90, fontsize=12)
ix = ix +1
if ix == 2:
fig = plt.figure(figsize = (55,12))
ix =1
plt.tight_layout()
**Avaliação**:
O plot acima procura mostrar a distribuição dos valores de contrato por UF, considerando-se todas as operações no período de 2002-2021. Desta forma, todas as UFs ja receberam montantes similares em algum momento - sendo que o maior valor ja contratado ocorreu no estado de PE.
oper_info_resumidas(df_nauto)
oper_info_resumidas(df_auto)
ano_min = np.min(df_consol['ano_contratacao'])
ano_max = np.max(df_consol['ano_contratacao'])
vlr_contr_soma_bi = df_consol['valor_contratado_reais'].sum()/1000000000 # em bilhoes
vlr_contr_soma_ano_bi = df_consol.groupby(['ano_contratacao'])['valor_contratado_reais'].sum()/1000000000 # em bilhoes
nticks = 19
print('Tabela de Valores Contratados (em bilhões) nos anos de %s a %s:' %(ano_min, ano_max))
df_consol_totais = (df_consol.groupby(['forma_de_apoio','tipo_oper','modalidade_de_apoio'])\
['valor_contratado_reais'].sum()/1000000000).reset_index()
df_consol_totais['Perc(%)'] = df_consol_totais['valor_contratado_reais']/vlr_contr_soma_bi*100
df_consol_totais
**Avaliação**:
t_vlr_mod_apoio = df_consol.groupby(['ano_contratacao','modalidade_de_apoio'])['valor_contratado_reais'].sum()/1000000
t_vlr_mod_apoio = t_vlr_mod_apoio.reset_index() # em mil
fig = px.bar(t_vlr_mod_apoio.sort_values(by=['ano_contratacao','modalidade_de_apoio'], ascending=[True,False]),
x='ano_contratacao', y='valor_contratado_reais', color='modalidade_de_apoio',
color_discrete_sequence=px.colors.qualitative.Safe,
barmode = 'stack', width=900, height=400)
fig.update_layout(title={'text': "Valores Contratados por Modalidade de apoio",
'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top'},
yaxis=dict(title='Valor Contratado (milhões)', titlefont_size=14,tickfont_size=14),
xaxis=dict(title=''),
legend=dict(x=0.05,y=0.95))
fig.update_xaxes(nticks=nticks)
fig.show()
# Retirando a coluna de modalidade de apoio
print('Tabela de Valores Contratados (em bilhões) nos anos de %s a %s:' %(ano_min, ano_max))
df_consol_totais = (df_consol.groupby(['forma_de_apoio','tipo_oper'])\
['valor_contratado_reais'].sum()/1000000000).reset_index()
df_consol_totais['Perc(%)'] = df_consol_totais['valor_contratado_reais']/vlr_contr_soma_bi*100
df_consol_totais
print('Tabela de Valores Contratados (em bilhões) - por Ano')
df_consol_tot_ano = (df_consol.groupby(['ano_contratacao','forma_de_apoio','tipo_oper'])\
['valor_contratado_reais'].sum()/1000000000)
df_consol_tot_ano_perc = df_consol_tot_ano /(df_consol_tot_ano.groupby('ano_contratacao').sum())*100
df_consol_totais_ano = pd.DataFrame({'valor_contratado_reais':df_consol_tot_ano,
'Perc(%)':df_consol_tot_ano_perc
}).reset_index()
df_consol_totais_ano
plot_val_contr_oper_apoio(df_consol)
**Avaliação**:
plot_evol_val_contr_desemb(df_nauto)
plot_evol_val_contr_desemb(df_auto)
# Carrega arquivo de PIB por municipio, anos 2002 a 2018
# ---------------------------------------------------------------
print('Carregando dados do PIB...')
pib = pd.read_csv('PIB_Mun_Consolidado.csv', sep='|', decimal=',', encoding='utf-8', low_memory=False)
columns_object = ['CodMun']
for c in columns_object:
pib[c] = pib[c].astype(int).astype(str)
pib_ano_min = np.min(pib['Ano'])
pib_ano_max = np.max(pib['Ano'])
print(' - Registros do PIB nos anos de %d a %d: %s' %(pib_ano_min, pib_ano_max, pib.shape[0]))
# Junta dados do IBGE (Pop2013) ao df de dados do PIB
# ---------------------------------------------------------------
print('Dados do IBGE (População) adicionados aos dados do PIB...')
pib_pop = pd.merge(pib, ibge[['SIGLA_UF','COD_IBGE', 'POP2013','CAPITAL']],
left_on=['UF','CodMun'], right_on=['SIGLA_UF','COD_IBGE'], how='left', indicator=True)
print(' - Registros do PIB que foram atualizados com dados do IBGE: ', pib_pop[pib_pop['_merge']=='both'].shape[0])
#display(pib_pop['_merge'].value_counts())
del pib_pop['_merge']
#Faixas População
faixas_pop = [0, 50000,500000,5000000,10000000,50000000]
pib_pop_faixas = pd.cut(pib_pop['POP2013'], bins=faixas_pop)
pib_pop_faixas_peso = pd.cut(pib_pop['POP2013'], bins=faixas_pop, labels=[50,100,250,500,2500])
pib_pop.insert(17, 'POP2013_Faixa', pib_pop_faixas)
pib_pop.insert(18, 'POP2013_Peso', pib_pop_faixas_peso)
pib_pop['POP2013_log'] = np.log10(pib_pop['POP2013']+0.01)
print('\nPesos e Faixas para dados de população: ')
print(' - Peso: 50 --> Faixa População [0, 50 mil]')
print(' - Peso: 100 --> Faixa População [50 mil, 500 mil]')
print(' - Peso: 250 --> Faixa População [500 mil, 5 milhões]')
print(' - Peso: 500 --> Faixa População [5 milhões, 10 milhões]')
print(' - Peso: 2500 --> Faixa População Acima 10 milhões')
print('\nAmostra dos dados de População, com faixa e peso:')
print('Obs. Nos plots, o peso representa a população dos municipios (pontos maiores, municípios mais populosos).')
display(pib_pop.iloc[:,16:20].head(5))
# Junta PIB_pop com df de Contratos por Municipio
# ---------------------------------------------------------------
lista_col_contr = ['ano_contratacao', 'uf', 'municipio_codigo',
'Soma_ValorContr','Soma_ValorContr_log',
'Menor_ValorContr', 'Maior_ValorContr','Total_Contr']
pib_contr = pd.merge(pib_pop, df_vlr_ano_mun[lista_col_contr],
left_on=['Ano','UF','CodMun'], right_on=['ano_contratacao','uf','municipio_codigo'],
how='left', indicator=True)
num_both = pib_contr[pib_contr['_merge']=='both'].shape[0]
print('Total de registros do dataframe PIB:', pib.shape[0])
print('Total de registros do dataframe de contratos:', df_vlr_ano_mun.shape[0])
print('Total de registros de PIB com dados de Contratos atualizados para cada Ano/ Municipio:', num_both)
print('Percentual de dados preenchidos: %s ' %np.round(num_both/df_vlr_ano_mun.shape[0]*100))
#display(pib_contr['_merge'].value_counts())
# Necessario colocar zero nos contratos
# municipios com PIB, mas sem investimentos em determinado ano)
# ---------------------------------------------------------------
pib_contr.loc[pib_contr['_merge']=='left_only', ['Soma_ValorContr','Soma_ValorContr_log',\
'Menor_ValorContr','Maior_ValorContr','Total_Contr']]=0
col_delete = ['ano_contratacao','uf','municipio_codigo']
for c in col_delete:
del pib_contr[c]
pib_contr = pib_contr.sort_values(by='Ano', ascending=True)
print('\nLista das Regioes: ', pib_contr['Regiao'].unique())
print('\nInformações por Municipio - Colunas do dataframe pib_contr: \n', pib_contr.columns.values)
# Parametros
# ---------------------------------------------------------------
'''
p_Regiao = lista das regioes de interesse
p_num_mun_UF = exibir TopN municipios de uma UF (default=1000)
p_yaxis = variavel socio-demografico no eixo y, para compara-la com os Valores de Investimentos
df = dataframe com informações socio-demograficas e de Contratos por Municipio
'''
def plot_evol_invest_municipio(df, p_Regiao, p_num_mun_UF, p_yaxis):
ix = 1
for R in p_Regiao:
if ix <= 1:
pib_contr2 = df.reset_index(drop=True)
df1 = pib_contr2[pib_contr2['Regiao']==R]
df1 = df1.groupby(['UF'])['Soma_ValorContr'].nlargest(p_num_mun_UF).reset_index()
indices = df1['level_1'].values
amostra = pib_contr2.iloc[indices]
amostra = amostra.sort_values(by='Ano')
fig = px.scatter(amostra, x='Soma_ValorContr', y=p_yaxis, size='POP2013_Peso', color='UF',
symbol='CAPITAL', symbol_sequence=['circle','star'],
animation_frame='Ano', animation_group='NomeMun', hover_name='NomeMun',
log_x=True, log_y=True, width=1000, height=800,
labels=dict(POP2013_Peso='PesoPop',Soma_ValorContr='Valor total dos Contratos no Municipio'),
color_discrete_sequence=px.colors.qualitative.Light24)
title = '<i><b>Regiao %s:</b></i>' %R + \
' <b>Evolução dos Investimentos com %s do Municipio' %p_yaxis + '</b> <br> \
Top %s municipios na UF (em valor contratado)' %p_num_mun_UF
fig.update_layout(title_text = title, title_x = 0.5, geo=dict(showframe = False,showcoastlines = True))
fig.update_traces(marker=dict(line=dict(width=1.1,color='DarkSlateGrey')),selector=dict(mode='markers'))
fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 1500
fig.layout.updatemenus[0].buttons[0].args[1]['transition']['duration'] = 1000
fig.show()
ix = ix +1
if ix == 2:
ix =1
# Parametros
# ---------------------------------------------------------------
p_Regiao = ['Norte', 'Sudeste', 'Sul', 'Centro-oeste', 'Nordeste']
p_num_mun_UF = 1000 # restringe para mostrar TopN municipios de uma UF
p_yaxis = 'PIB_perCapita'
plot_evol_invest_municipio(pib_contr, p_Regiao, p_num_mun_UF, p_yaxis)
# Parametros
# ---------------------------------------------------------------
p_Regiao = ['Norte', 'Sudeste', 'Sul', 'Centro-oeste', 'Nordeste']
p_num_mun_UF = 1000 # restringe para mostrar TopN municipios de uma UF
p_yaxis = 'PIB_Agropecuaria'
plot_evol_invest_municipio(pib_contr, p_Regiao, p_num_mun_UF, p_yaxis)
# Parametros
# ---------------------------------------------------------------
p_Regiao = ['Norte', 'Sudeste', 'Sul', 'Centro-oeste', 'Nordeste']
p_num_mun_UF = 1000 # restringe para mostrar TopN municipios de uma UF
p_yaxis = 'PIB_Industria'
plot_evol_invest_municipio(pib_contr, p_Regiao, p_num_mun_UF, p_yaxis)
# Parametros
# ---------------------------------------------------------------
p_Regiao = ['Norte', 'Sudeste', 'Sul', 'Centro-oeste', 'Nordeste']
p_num_mun_UF = 1000 # restringe para mostrar TopN municipios de uma UF
p_yaxis = 'PIB_Serv'
plot_evol_invest_municipio(pib_contr, p_Regiao, p_num_mun_UF, p_yaxis)